#ifndef _PROPERTYGRAMMAR_H_
#define _PROPERTYGRAMMAR_H_

#include "IPropertyActions.h"
#include "Parsers/GrammarErrorHandler.hpp"

//#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp> 

#include <iostream>

namespace spirit = boost::spirit;
namespace qi	= boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
namespace phoenix = boost::phoenix;


namespace GST{
namespace Parsers{

//
// the grammar
//
template <typename Iterator/*, typename Skipper*/>
class PropertyGrammar : public qi::grammar<Iterator/*, Skipper*/>
{
public:
    PropertyGrammar(boost::shared_ptr<IPropertyActions> actions) 
		: PropertyGrammar::base_type(propertyString_) //define here the base rule
		, _actions(actions)
    {
		using qi::lit;
		using qi::char_;
		using qi::lexeme;
		using qi::space;
		using ascii::string;

		//define here function pointers to Semantic actions (more beautiful grammar definiton)
		typedef boost::function< void( qi::unused_type, qi::unused_type, qi::unused_type  ) >		void_action;
		typedef boost::function< void( const std::string&, qi::unused_type, qi::unused_type  ) >	value_action;
		typedef boost::function< void( const std::vector<std::string>&, qi::unused_type, qi::unused_type  ) >	vector_action;

		void_action			nextObject(boost::bind(&IPropertyActions::PropNextObject			, _actions ));
		value_action		addValue(boost::bind(&IPropertyActions::PropAddValue				, _actions, ::_1 ));
		vector_action		addVector(boost::bind(&IPropertyActions::PropAddVector				, _actions, ::_1 ));

		//
		//###  the grammar definiton   ###
		value_ 
			%= lexeme[ *(char_ - (lit(';') ^ lit('}') ^ lit(')'))) ]
		; 

		array_
			= lit('{')
			>  value_ % ';'
			> lit('}')
		;

		entry_
			= array_[addVector] | value_[addValue]
		;

		oneObject_
			= lit('(')
			> -( entry_ > *( lit(';') > entry_ ) )
			> lit(')')
		;

		propertyString_ 
			= oneObject_[nextObject]
			> *( lit(';') > oneObject_[nextObject] )
		;
		//### end of grammar definiton ###
		//

		//
		//### error handling			
		entry_.name(						"entry_");
		array_.name(						"array_");
		value_.name(						"value_");
		oneObject_.name(					"oneObject_");
		propertyString_.name(				"propertyString_");		

		namespace qil = qi::labels;

		qi::on_error<qi::fail>(propertyString_,
							   error_handler_func(error_handler())(
									   qil::_1, qil::_2, qil::_3, qil::_4));
		//### end of error handling
		//

    } //end of c'tor

	qi::rule<Iterator/*, Skipper*/> propertyString_;
	qi::rule<Iterator/*, Skipper*/> oneObject_;
	qi::rule<Iterator/*, Skipper*/> entry_;
	qi::rule<Iterator, std::string()/*, Skipper*/> value_;
	qi::rule<Iterator, std::vector<std::string>()/*, Skipper*/> array_;

	

private:
	boost::shared_ptr<IPropertyActions> _actions;
};

}// namespace Parsers
}// namespace GST

#endif //_PROPERTYGRAMMAR_H_